package com.gzdh.tang.ali.rule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gzdh.tang.ali.model.OuterExtends;
import com.gzdh.tang.comm.constant.SpringContextUtils;
import com.gzdh.tang.comm.handler.IPayRuleHandler;
import com.gzdh.tang.mobile.entity.Kl;
import com.gzdh.tang.mobile.service.KlService;
import com.gzdh.tang.modu.entity.*;
import com.gzdh.tang.modu.model.QrRestrictionsModel;
import com.gzdh.tang.modu.service.*;
import com.gzdh.tang.modu.util.DateUtil;
import com.gzdh.tang.warehouse.service.DeviceService;
import com.gzdh.tang.warehouse.service.InStockService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;

@Slf4j
public class AliFeRule implements IPayRuleHandler {


    FkService fkService;

    GsService gsService;

    MacMainpSbruanService macMainpSbruanService;

    MacMainpSbruanDinnerService macMainpSbruanDinnerService;

    MacMainpSbruanKlService macMainpSbruanKlService;

    ReserveService reserveService;

    ReserveXfjTempService reserveXfjTempService;

    TangDeviceService tangDeviceService;

    DeviceService deviceService;

    InStockService inStockService;

    MacMainpSbruanKlDinnerService macMainpSbruanKlDinnerService;

    MacMainpSbruanKlButieService macMainpSbruanKlButieService;

    MacMainpSbruanOrdersService macMainpSbruanOrdersService;

    KlService klService;

    TangAddrService tangAddrService;

    AliCardAgreementService aliCardAgreementService;

    public AliFeRule() {
        fkService = (FkService) SpringContextUtils.getBean("fkServiceImpl");
        gsService = (GsService) SpringContextUtils.getBean("gsService");
        macMainpSbruanService = (MacMainpSbruanService) SpringContextUtils.getBean("macMainpSbruanService");
        macMainpSbruanDinnerService = (MacMainpSbruanDinnerService) SpringContextUtils.getBean("macMainpSbruanDinnerService");
        macMainpSbruanKlService = (MacMainpSbruanKlService) SpringContextUtils.getBean("macMainpSbruanKlService");
        reserveService = (ReserveService) SpringContextUtils.getBean("reserveService");
        tangDeviceService = (TangDeviceService) SpringContextUtils.getBean("tangDeviceServiceImpl");
        deviceService = (DeviceService) SpringContextUtils.getBean("deviceServiceImpl");
        inStockService = (InStockService) SpringContextUtils.getBean("inStockService");
        macMainpSbruanKlDinnerService = (MacMainpSbruanKlDinnerService) SpringContextUtils.getBean("macMainpSbruanKlPriceService");
        macMainpSbruanKlButieService = (MacMainpSbruanKlButieService) SpringContextUtils.getBean("macMainpSbruanKlButieService");
        klService = (KlService) SpringContextUtils.getBean("klService");
        reserveXfjTempService = (ReserveXfjTempService) SpringContextUtils.getBean("reserveServiceXfjTemp");
        tangAddrService = (TangAddrService) SpringContextUtils.getBean("tangAddrServiceImpl");
        aliCardAgreementService = (AliCardAgreementService) SpringContextUtils.getBean("aliCardAgreementServiceImpl");
        macMainpSbruanOrdersService = (MacMainpSbruanOrdersService) SpringContextUtils.getBean("macMainpSbruanOrdersServiceImpl");
    }


    @Override
    public JSONObject toCardPay(JSONObject params) throws RuntimeException {
        //缺省支付，默认插入到reserve即可操作
        String deviceId = params.getString("deviceId");
        String price = params.getString("price");
        String cardsn = params.getString("auth");
        String orders = params.getString("orders");
        int onLine = params.getInteger("onLine");
        String dateStr = params.getString("dateStr");
        JSONObject jsonObject = new JSONObject();
        jsonObject.putAll(params);
        Date date = new Date();
        if (onLine > 0) {
            try {
                date = new SimpleDateFormat("yyyyMMddHHmmssSSS").parse(dateStr);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            Fk fk = fkService.getOne(new QueryWrapper<Fk>().lambda().eq(Fk::getCardsn, cardsn));
            if (fk == null) {
                throw new RuntimeException("非法卡");
            }
            Kl kl = klService.getOne(new QueryWrapper<Kl>().lambda().eq(Kl::getBm, fk.getKl()));
            if (kl != null && kl.getValid() == 1) {
                //判断有效期
                if (fk.getValiddate().compareTo(new Date()) < 0) {
                    throw new RuntimeException("超过有效期");
                }
            }
            jsonObject.put("fk", fk);
            MacMainpSbruan macMainpSbruan = macMainpSbruanService.getOne(new QueryWrapper<MacMainpSbruan>().lambda().eq(MacMainpSbruan::getMac, deviceId));
            try {
                String dinner = getDinner(macMainpSbruan).trim();
                macMainpSbruan.setDinner(dinner);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("餐次获取失败");
            }
            MacMainpSbruanKlButie macMainpSbruanKlButie = macMainpSbruanKlButieService.getOne(new QueryWrapper<MacMainpSbruanKlButie>()
                    .lambda().eq(MacMainpSbruanKlButie::getDinner, macMainpSbruan.getDinner()).eq(MacMainpSbruanKlButie::getKl, fk.getKl()));
            if (macMainpSbruanKlButie == null) {
                throw new RuntimeException("优惠有误请设置");
            }
            String payedPrice = reserveService.priceReserve(fk.getCardno(), macMainpSbruan.getDinner());
            JSONObject priceRule = judgYouhui(macMainpSbruanKlButie, price, payedPrice,
                    "1".equals(macMainpSbruan.getDinner()) ? fk.getZbtcs() : fk.getBtcs(),onLine);
            Fk fk1 = cardToReserve2(deviceId, orders, macMainpSbruan, macMainpSbruanKlButie.getButie(), fk, priceRule, onLine, date);

            jsonObject.put("fk", fk1);
            jsonObject.put("success", true);
            jsonObject.put("msg", "支付成功");
            jsonObject.put("userName", fk.getName());
            jsonObject.put("amount", price);
            List<OuterExtends> outerExtendsList = new ArrayList<>();
            outerExtendsList.add(addOutOuterExtends("姓名", fk.getName()));
            outerExtendsList.add(addOutOuterExtends("消费金额", price));
            outerExtendsList.add(addOutOuterExtends("卡余额", fk1.getKye()));
            outerExtendsList.add(addOutOuterExtends("补贴余额", fk1.getBtye()));
            jsonObject.put("outerExtends", outerExtendsList);
        } catch (Exception e) {
            e.printStackTrace();
            jsonObject.put("success", false);
            jsonObject.put("msg", e.getMessage());
        }
        return jsonObject;
    }

    @Override
    public JSONObject toCashPay(JSONObject params) throws RuntimeException {
        return null;
    }

    @Override
    public JSONObject toQrPay(JSONObject params) throws RuntimeException {
        JSONObject jsonObject = new JSONObject();
        jsonObject.putAll(params);
        //授权码，付款码或者电子饭卡
        String auth = params.getString("auth");
        int authType = 0;
        if (auth.length() < 19 && "1".equals(auth.substring(0, 1))) {
            //微信
            jsonObject.putAll(weixinQrPay(params));
        } else if (auth.length() < 19 && "2".equals(auth.substring(0, 1))) {
            //支付宝
            jsonObject.putAll(aliQrPay(params));
        } else {
            //其他，需要解码
            jsonObject.putAll(dzkPay(params));
        }
        return jsonObject;
    }

    public JSONObject aliQrPay(JSONObject params) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("success", false);
        jsonObject.put("msg", "请使用电子饭卡");
        return jsonObject;
    }

    public JSONObject weixinQrPay(JSONObject params) {
        JSONObject jsonObject = new JSONObject();
        String price = params.getString("price");
        price = new BigDecimal(price).multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString();
        String orders = params.getString("orders");
        String auth = params.getString("auth");
        String deviceId = params.getString("deviceId");
        jsonObject.put("success", false);
        jsonObject.put("msg", "请使用电子饭卡");
        return jsonObject;
    }

    public JSONObject dzkPay(JSONObject params) {
//        String authStr = params.getString("auth");
        String deviceId = params.getString("deviceId");
        JSONObject jsonObject = new JSONObject();
        jsonObject.putAll(params);

        MacMainpSbruan macMainpSbruan = macMainpSbruanService.getOne(new QueryWrapper<MacMainpSbruan>().lambda().eq(MacMainpSbruan::getMac, deviceId));
        QrRestrictionsModel qrRestrictionsModel = JSONObject.toJavaObject(JSONObject.parseObject(macMainpSbruan.getQrRestrictions()), QrRestrictionsModel.class);
        Fk fk = null;
        switch (qrRestrictionsModel.getDzkRestrictions()) {
            case 0:
                jsonObject.put("success", false);
                jsonObject.put("msg", "当前模式尚未开通");
                return jsonObject;
            case 1:
                //使用BASE64解码方式
                String authStr = params.getString("auth");
                byte[] bytes = Base64.getDecoder().decode(authStr);
                String json = new String(bytes);
                try {
                    String cardno = json.split(",")[0].split("=")[1];
                    String dates = json.split(",")[2].split("=")[1];
                    String nowDate = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date(System.currentTimeMillis() - (2 * (60 * 1000) * 60)));
                    if (new BigDecimal(nowDate).compareTo(new BigDecimal(dates)) > 0) {
                        throw new RuntimeException("二维码已过期");
                    }
                    fk = fkService.getOne(new QueryWrapper<Fk>().lambda().eq(Fk::getCardno, cardno));
                } catch (Exception e) {
                    jsonObject.put("success", false);
                    jsonObject.put("msg", e.getMessage());
                    return jsonObject;
                }
                break;
            case 2:
                //通过数据库读取，获取一次解码
                fk = fkService.getFkByQr2(params.getString("auth"));
                break;
        }
        String price = params.getString("price");
        String orders = params.getString("orders");
        try {
            if (fk == null) {
                throw new RuntimeException("查无此人");
            }
//             fk = fkService.getOne(new QueryWrapper<Fk>().lambda().eq(Fk::getCardno, cardno));
            jsonObject.put("fk", fk);
            Kl kl = klService.getOne(new QueryWrapper<Kl>().lambda().eq(Kl::getBm, fk.getKl()));
            if (kl != null && kl.getValid() == 1) {
                //判断有效期
                if (fk.getValiddate().compareTo(new Date()) < 0) {
                    throw new RuntimeException("超过有效期");
                }
            }
//            MacMainpSbruan macMainpSbruan = macMainpSbruanService.getOne(new QueryWrapper<MacMainpSbruan>().lambda().eq(MacMainpSbruan::getMac, deviceId));
            try {
                String dinner = getDinner(macMainpSbruan).trim();
                macMainpSbruan.setDinner(dinner);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("餐次获取失败");
            }
            List<MacMainpSbruanKl> macMainpSbruanKlList = macMainpSbruanKlService
                    .list(new QueryWrapper<MacMainpSbruanKl>().lambda().eq(MacMainpSbruanKl::getDeviceId, macMainpSbruan.getId()));
            if (!judeKl(macMainpSbruanKlList, fk.getKl())) {
                throw new RuntimeException("不支持此卡类");
            }
            MacMainpSbruanKlButie macMainpSbruanKlButie = macMainpSbruanKlButieService
                    .getOne(new QueryWrapper<MacMainpSbruanKlButie>().lambda().eq(MacMainpSbruanKlButie::getDinner,
                            macMainpSbruan.getDinner()).eq(MacMainpSbruanKlButie::getKl, fk.getKl()));

            if (macMainpSbruanKlButie == null) {
                throw new RuntimeException("优惠有误请设置");
            }
            String payedPrice = reserveService.priceReserve(fk.getCardno(), macMainpSbruan.getDinner());
            JSONObject priceRule = judgYouhui(macMainpSbruanKlButie, price, payedPrice,
                    "1".equals(macMainpSbruan.getDinner()) ? fk.getZbtcs() : fk.getBtcs(),0);
//            JSONObject priceRule = judgYouhui(macMainpSbruanKlButie, price); 1150 1.6

            cardToReserve2(deviceId, orders, macMainpSbruan, macMainpSbruanKlButie.getButie(), fk, priceRule, 0, new Date());
            jsonObject.put("fk", fk);
            jsonObject.put("success", true);
            jsonObject.put("msg", "支付成功");
            jsonObject.put("userName", fk.getName());
            jsonObject.put("amount", priceRule.getString("aPrice"));
            List<OuterExtends> outerExtendsList = new ArrayList<>();
            outerExtendsList.add(addOutOuterExtends("姓名", fk.getName()));
            outerExtendsList.add(addOutOuterExtends("原消费金额", price));
            outerExtendsList.add(addOutOuterExtends("优惠金额", priceRule.getString("yPrice")));
            outerExtendsList.add(addOutOuterExtends("卡余额", fk.getKye()));
            outerExtendsList.add(addOutOuterExtends("补贴余额", fk.getBtye()));
            jsonObject.put("outerExtends", outerExtendsList);
        } catch (Exception e) {
            e.printStackTrace();
            jsonObject.put("success", false);
            jsonObject.put("msg", e.getMessage());
        }
        return jsonObject;
    }

    private String getDinner(MacMainpSbruan macMainpSbruan) throws Exception {
        String hourMin = new SimpleDateFormat("HH:mm").format(new Date());
        List<MacMainpSbruanDinner> macMainpSbruanDinnerList = macMainpSbruanDinnerService
                .list(new QueryWrapper<MacMainpSbruanDinner>().lambda().eq(MacMainpSbruanDinner::getDeviceId, macMainpSbruan.getId()));
        for (MacMainpSbruanDinner goo : macMainpSbruanDinnerList) {
            if (DateUtil.hourMinuteBetween(hourMin, goo.getStartTime(), goo.getEndTime())) {
                return goo.getDinner();
            }
        }
        throw new Exception("未找到该灶类");
    }

    private boolean judeKl(List<MacMainpSbruanKl> macMainpSbruanKlList, String kl) {
        for (MacMainpSbruanKl goo : macMainpSbruanKlList) {
            if (goo.getKl().equals(kl.trim())) {
                return true;
            }
        }
        return false;
    }


    @Override
    public JSONObject toFacePay(JSONObject params) throws RuntimeException {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("success", false);
        jsonObject.put("msg", "该功能尚未开通");
        return jsonObject;
    }


    private OuterExtends addOutOuterExtends(String name, String value) {
        OuterExtends outerExtends = new OuterExtends();
        outerExtends.setTitle(name);
        outerExtends.addDetail(name, value);
        return outerExtends;
    }

    private JSONObject judgYouhui(MacMainpSbruanKlButie macMainpSbruanKlButie, String priceStr, String payedPrice, int counts, int onLine) throws RuntimeException {
        BigDecimal price = new BigDecimal(priceStr);
        if (StringUtils.isEmpty(payedPrice)) {
            payedPrice = "0";
        }
        JSONObject jsonObject = new JSONObject();

        if (macMainpSbruanKlButie.getType() == 1) {
            //直接减扣
            if (price.compareTo(new BigDecimal(macMainpSbruanKlButie.getButie())) <= 0) {
                jsonObject.put("aPrice", "0");
                jsonObject.put("price", priceStr);
                jsonObject.put("yPrice", price.toPlainString());
                return jsonObject;
            } else {
                jsonObject.put("aPrice", price.subtract(new BigDecimal(macMainpSbruanKlButie.getButie())).toPlainString());
                jsonObject.put("price", priceStr);
                jsonObject.put("yPrice", macMainpSbruanKlButie.getButie());
                return jsonObject;
            }
        } else if (macMainpSbruanKlButie.getType() == 2) {
            //折扣比例
            //优惠后金额
            BigDecimal affPrice = price.multiply((new BigDecimal(macMainpSbruanKlButie.getButie()).divide(new BigDecimal(100),
                    2, RoundingMode.HALF_UP)));
            affPrice = affPrice.setScale(2, RoundingMode.HALF_UP);
            jsonObject.put("aPrice", affPrice.toPlainString());  //支付金额
            jsonObject.put("price", priceStr);
            jsonObject.put("yPrice", price.subtract(affPrice));  //优惠的金额
        } else if (macMainpSbruanKlButie.getType() == 3) {
            //计算补贴
            JSONObject restrictionsJson = JSON.parseObject(macMainpSbruanKlButie.getRestrictions());
            BigDecimal minPrice = new BigDecimal(restrictionsJson.getString("minPrice"));   //最低需要消费补贴金额，没达到将不享有优惠补贴
            BigDecimal maxPay = new BigDecimal(restrictionsJson.getString("maxDinnerPay")); //最大支付金额;
            BigDecimal minPayPrice = new BigDecimal(macMainpSbruanKlButie.getMinPrice());       //本次消费最低保证金额;
            if (new BigDecimal(payedPrice).add(price).compareTo(maxPay) > 0 && onLine == 0) {
                //抛出异常，达到最大消费金额

                throw new RuntimeException("到达最大消费金额,扣款失败");
            }
//            if (counts <= 0) {
//                jsonObject.put("aPrice", priceStr);
//                jsonObject.put("price", priceStr);
//                jsonObject.put("yPrice", "0");
//                return jsonObject;
//            }
            if (price.compareTo(minPrice) <= 0 || counts <= 0) {
                //达不到优惠条件
                jsonObject.put("aPrice", priceStr);
                jsonObject.put("price", priceStr);
                jsonObject.put("yPrice", "0");
                return jsonObject;
            }

            BigDecimal numPrice = price.add(minPayPrice);
            if (price.compareTo(new BigDecimal(macMainpSbruanKlButie.getButie())) <= 0) {
                //第一和二方案
                //当前金额减最低扣款金额，得出补贴金额
                jsonObject.put("aPrice", minPayPrice.toPlainString());//补贴金额
                jsonObject.put("price", priceStr);
                jsonObject.put("yPrice", price.subtract(minPayPrice).toPlainString());
                return jsonObject;
            } else {
                BigDecimal priceTemp = price.subtract(minPayPrice);//参与计算优惠
                if (priceTemp.compareTo(new BigDecimal(macMainpSbruanKlButie.getButie())) <= 0) {
                    jsonObject.put("aPrice", minPayPrice.toPlainString());//补贴金额
                    jsonObject.put("price", priceStr);
                    jsonObject.put("yPrice", price.subtract(minPayPrice).toPlainString());
                    return jsonObject;
                } else {
                    jsonObject.put("aPrice", price.subtract(new BigDecimal(macMainpSbruanKlButie.getButie())));//补贴金额
                    jsonObject.put("price", priceStr);
                    jsonObject.put("yPrice", macMainpSbruanKlButie.getButie());
                }
                return jsonObject;
            }
        }

        return jsonObject;
    }

    private Fk cardToReserve2(String deviceId, String reqSeqNo, MacMainpSbruan macMainpSbruan,
                              String zkl, Fk fk, JSONObject priceRule, int type, Date date) throws RuntimeException {
        BigDecimal xfPrice = new BigDecimal(priceRule.getString("aPrice"));
        if (type <= 0) {
            if (xfPrice.compareTo(new BigDecimal(fk.getKye())) > 0) {
                throw new RuntimeException("余额不足");
            }
            int count = gsService.count(new QueryWrapper<Gs>().lambda().eq(Gs::getKh, fk.getKh()).eq(Gs::getCardno, fk.getCardno()));
            if (count > 0) {
                throw new RuntimeException("此卡已挂失,请回收");
            }
        }
        BigDecimal yPrice = new BigDecimal(priceRule.getString("yPrice"));
        if (yPrice.compareTo(new BigDecimal(0)) > 0) {
            insertReserve(deviceId, String.valueOf(reqSeqNo), new BigDecimal(priceRule.getString("yPrice")).multiply(new BigDecimal(100)).intValue(),
                    1, fk, macMainpSbruan, "现金菜", macMainpSbruan.getCode(),
                    yPrice, "1", zkl, String.valueOf(reqSeqNo), priceRule, date);
            if ("1".equals(macMainpSbruan.getDinner())) {
                //早餐;
                fkService.lambdaUpdate().set(Fk::getZbtcs, fk.getZbtcs() - 1).eq(Fk::getCardno, fk.getCardno()).update();
            } else {
                fkService.lambdaUpdate().set(Fk::getBtcs, fk.getBtcs() - 1).eq(Fk::getCardno, fk.getCardno()).update();
            }
        }
        date = new Date(date.getTime() + 100);
        insertReserve(deviceId, String.valueOf(reqSeqNo), xfPrice.multiply(new BigDecimal(100)).intValue(),
                1, fk, macMainpSbruan, "现金菜", macMainpSbruan.getCode(),
                new BigDecimal(fk.getKye()), "0", zkl, String.valueOf(reqSeqNo), priceRule, date);
        fk.setKye(new BigDecimal(fk.getKye()).subtract(xfPrice).toPlainString());

        return fk;
    }


    public boolean insertReserve(String rgTermSN, String reqSeqNo, int price, int sl, Fk fk, MacMainpSbruan macMainpSbruan,
                                 String hName, String code, BigDecimal cardPrice, String sc, String zkl, String orders,
                                 JSONObject priceRule, Date date) throws RuntimeException {
        BigDecimal xfPrice = (new BigDecimal(price).divide(new BigDecimal(100))).multiply(new BigDecimal(sl));
        BigDecimal yePrice = new BigDecimal(0);

        yePrice = cardPrice.subtract(xfPrice);
        Reserve reserve = new Reserve();
        reserve.setZkl(zkl);
        reserve.setCardno(fk.getCardno());
        reserve.setZl(macMainpSbruan.getZl());
        reserve.setBqh(macMainpSbruan.getBqh());
        reserve.setKsh(macMainpSbruan.getKsh());
        reserve.setBed("0");
        reserve.setPosnum(macMainpSbruan.getPos());
        reserve.setDinner(macMainpSbruan.getDinner());
        reserve.setCode(code);
        reserve.setSl(sl);
        reserve.setStatus("1");
//        reserve.setDiscountAmount(priceRule.getString("yPrice"));
//        reserve.setOriginalAmount(priceRule.getString("price"));
        reserve.setJe(xfPrice.toPlainString());
        try {
            reserve.setYe(yePrice.setScale(2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString());
        } catch (Exception e) {

            reserve.setYe("0");
        }
        reserve.setKl(fk.getKl());
        reserve.setSc(sc);
        reserve.setLsh2(String.valueOf(reqSeqNo));
        reserve.setCzrq(date);
        reserve.setDcrq(new SimpleDateFormat("yyyy-MM-dd 00:00:00").format(new Date()));
        reserve.setHname(hName);
        reserve.setSddz(rgTermSN);
        reserve.setCs(0);
        reserve.setOpenid(fk.getCardsn());
        reserve.setKehu(fk.getName());
        reserve.setZfserialnumber(orders);
        reserve.setAddr(macMainpSbruan.getAddr());
        reserveService.save(reserve);
        return true;
    }
}
